package com.wondertek.onvif.connection;

import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * HTTP连接池管理器
 * 管理和复用HTTP连接，提高性能
 */
@Slf4j
@Component
public class ConnectionPoolManager {
    
    private static final Logger log = LoggerFactory.getLogger(ConnectionPoolManager.class);
    
    /**
     * 连接池，按主机分组
     */
    private final ConcurrentHashMap<String, ConnectionPool> connectionPools = new ConcurrentHashMap<>();
    
    /**
     * 清理任务调度器
     */
    private final ScheduledExecutorService cleanupScheduler = Executors.newSingleThreadScheduledExecutor(r -> {
        Thread t = new Thread(r, "ConnectionPool-Cleanup");
        t.setDaemon(true);
        return t;
    });
    
    /**
     * 最大连接数（每个主机）
     */
    private static final int MAX_CONNECTIONS_PER_HOST = 10;
    
    /**
     * 连接空闲超时时间（毫秒）
     */
    private static final long CONNECTION_IDLE_TIMEOUT = 30000; // 30秒
    
    /**
     * 清理任务执行间隔（毫秒）
     */
    private static final long CLEANUP_INTERVAL = 60000; // 1分钟
    
    public ConnectionPoolManager() {
        // 启动定期清理任务
        cleanupScheduler.scheduleWithFixedDelay(
            this::cleanupIdleConnections,
            CLEANUP_INTERVAL,
            CLEANUP_INTERVAL,
            TimeUnit.MILLISECONDS
        );
        log.info("连接池管理器已启动，清理间隔: {}ms", CLEANUP_INTERVAL);
    }
    
    /**
     * 获取HTTP连接
     * 
     * @param url 目标URL
     * @param connectTimeout 连接超时时间
     * @param readTimeout 读取超时时间
     * @return HTTP连接
     */
    public HttpURLConnection getConnection(URL url, int connectTimeout, int readTimeout) {
        String host = url.getHost() + ":" + getPort(url);
        ConnectionPool pool = connectionPools.computeIfAbsent(host, k -> new ConnectionPool(k));
        
        try {
            HttpURLConnection connection = pool.borrowConnection(url, connectTimeout, readTimeout);
            log.debug("从连接池获取连接: {}, 池状态: {}", host, pool.getStatus());
            return connection;
        } catch (Exception e) {
            log.warn("从连接池获取连接失败: {}, 创建新连接", host, e);
            return createNewConnection(url, connectTimeout, readTimeout);
        }
    }
    
    /**
     * 为海康设备创建新的连接（不使用连接池，避免连接复用问题）
     */
    public HttpURLConnection createFreshConnection(URL url, int connectTimeout, int readTimeout) {
        try {
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(connectTimeout);
            connection.setReadTimeout(readTimeout);
            connection.setUseCaches(false);
            connection.setInstanceFollowRedirects(false);
            
            // 针对海康设备优化的连接参数
            String host = url.getHost().toLowerCase();
            if (isHikvisionDevice(host)) {
                // 海康设备专用设置，避免"Unexpected end of file"错误
                connection.setRequestProperty("Connection", "close"); // 强制关闭连接
                connection.setRequestProperty("Cache-Control", "no-cache");
                connection.setRequestProperty("Pragma", "no-cache");
                connection.setRequestProperty("User-Agent", "ONVIF-Client/1.0");
                connection.setRequestProperty("Accept", "application/soap+xml, text/xml, */*");
                connection.setRequestProperty("Accept-Encoding", "identity"); // 禁用压缩
                log.debug("为海康设备创建优化连接: {}", url);
            } else {
                // 通用设备设置
                connection.setRequestProperty("User-Agent", "ONVIF-Manager/1.0");
                connection.setRequestProperty("Accept", "*/*");
                connection.setRequestProperty("Connection", "close");
                log.debug("创建通用HTTP连接: {}", url);
            }
            
            return connection;
        } catch (Exception e) {
            throw new RuntimeException("创建HTTP连接失败: " + url, e);
        }
    }
    
    /**
     * 判断是否为海康设备
     */
    private boolean isHikvisionDevice(String host) {
        return host != null && (
            host.contains("hikvision") ||
            host.contains("hik") ||
            host.contains("ds-") ||
            host.matches(".*\\b(192\\.168\\.|10\\.|172\\.(1[6-9]|2[0-9]|3[01])\\.).*") // 常见内网IP
        );
    }
    
    /**
     * 归还连接到池中
     * 
     * @param connection HTTP连接
     */
    public void returnConnection(HttpURLConnection connection) {
        if (connection == null) {
            return;
        }
        
        try {
            URL url = connection.getURL();
            String host = url.getHost() + ":" + getPort(url);
            ConnectionPool pool = connectionPools.get(host);
            
            if (pool != null) {
                pool.returnConnection(connection);
                log.debug("连接已归还到池: {}, 池状态: {}", host, pool.getStatus());
            } else {
                connection.disconnect();
                log.debug("连接池不存在，直接关闭连接: {}", host);
            }
        } catch (Exception e) {
            log.warn("归还连接时发生错误", e);
            try {
                connection.disconnect();
            } catch (Exception ex) {
                log.debug("关闭连接时发生错误", ex);
            }
        }
    }
    
    /**
     * 创建新的HTTP连接
     * 
     * @param url 目标URL
     * @param connectTimeout 连接超时时间
     * @param readTimeout 读取超时时间
     * @return HTTP连接
     */
    private HttpURLConnection createNewConnection(URL url, int connectTimeout, int readTimeout) {
        try {
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(connectTimeout);
            connection.setReadTimeout(readTimeout);
            connection.setUseCaches(false);
            connection.setInstanceFollowRedirects(false);
            return connection;
        } catch (Exception e) {
            throw new RuntimeException("创建HTTP连接失败: " + url, e);
        }
    }
    
    /**
     * 获取URL的端口号
     * 
     * @param url URL对象
     * @return 端口号
     */
    private int getPort(URL url) {
        int port = url.getPort();
        if (port == -1) {
            return "https".equals(url.getProtocol()) ? 443 : 80;
        }
        return port;
    }
    
    /**
     * 清理空闲连接
     */
    private void cleanupIdleConnections() {
        try {
            long currentTime = System.currentTimeMillis();
            int totalCleaned = 0;
            
            for (ConnectionPool pool : connectionPools.values()) {
                int cleaned = pool.cleanupIdleConnections(currentTime, CONNECTION_IDLE_TIMEOUT);
                totalCleaned += cleaned;
            }
            
            // 移除空的连接池
            connectionPools.entrySet().removeIf(entry -> entry.getValue().isEmpty());
            
            if (totalCleaned > 0) {
                log.debug("清理了 {} 个空闲连接，剩余连接池: {}", totalCleaned, connectionPools.size());
            }
        } catch (Exception e) {
            log.warn("清理空闲连接时发生错误", e);
        }
    }
    
    /**
     * 获取连接池状态
     * 
     * @return 状态信息
     */
    public String getPoolStatus() {
        StringBuilder sb = new StringBuilder();
        sb.append("连接池状态:\n");
        
        for (Map.Entry<String, ConnectionPool> entry : connectionPools.entrySet()) {
            sb.append(String.format("  %s: %s\n", entry.getKey(), entry.getValue().getStatus()));
        }
        
        return sb.toString();
    }
    
    /**
     * 关闭连接池管理器
     */
    @PreDestroy
    public void shutdown() {
        log.info("正在关闭连接池管理器...");
        
        // 停止清理任务
        cleanupScheduler.shutdown();
        
        try {
            if (!cleanupScheduler.awaitTermination(5, TimeUnit.SECONDS)) {
                cleanupScheduler.shutdownNow();
            }
        } catch (InterruptedException e) {
            cleanupScheduler.shutdownNow();
            Thread.currentThread().interrupt();
        }
        
        // 关闭所有连接池
        for (ConnectionPool pool : connectionPools.values()) {
            pool.shutdown();
        }
        connectionPools.clear();
        
        log.info("连接池管理器已关闭");
    }
    
    /**
     * 单个主机的连接池
     */
    private static class ConnectionPool {
        private final String host;
        private final ConcurrentHashMap<HttpURLConnection, Long> availableConnections = new ConcurrentHashMap<>();
        private final AtomicInteger totalConnections = new AtomicInteger(0);
        
        public ConnectionPool(String host) {
            this.host = host;
        }
        
        /**
         * 借用连接
         */
        public HttpURLConnection borrowConnection(URL url, int connectTimeout, int readTimeout) throws Exception {
            // 尝试复用现有连接
            for (Map.Entry<HttpURLConnection, Long> entry : availableConnections.entrySet()) {
                HttpURLConnection connection = entry.getKey();
                if (availableConnections.remove(connection) != null) {
                    // 检查连接是否仍然有效
                    if (isConnectionValid(connection)) {
                        return connection;
                    } else {
                        connection.disconnect();
                        totalConnections.decrementAndGet();
                    }
                }
            }
            
            // 创建新连接
            if (totalConnections.get() < MAX_CONNECTIONS_PER_HOST) {
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setConnectTimeout(connectTimeout);
                connection.setReadTimeout(readTimeout);
                connection.setUseCaches(false);
                connection.setInstanceFollowRedirects(false);
                totalConnections.incrementAndGet();
                return connection;
            }
            
            throw new RuntimeException("连接池已满: " + host);
        }
        
        /**
         * 归还连接
         */
        public void returnConnection(HttpURLConnection connection) {
            if (connection != null && isConnectionValid(connection)) {
                availableConnections.put(connection, System.currentTimeMillis());
            } else if (connection != null) {
                connection.disconnect();
                totalConnections.decrementAndGet();
            }
        }
        
        /**
         * 检查连接是否有效
         */
        private boolean isConnectionValid(HttpURLConnection connection) {
            try {
                // 简单检查连接是否仍然可用
                return connection != null && connection.getURL() != null;
            } catch (Exception e) {
                return false;
            }
        }
        
        /**
         * 清理空闲连接
         */
        public int cleanupIdleConnections(long currentTime, long idleTimeout) {
            int cleaned = 0;
            
            for (Map.Entry<HttpURLConnection, Long> entry : availableConnections.entrySet()) {
                if (currentTime - entry.getValue() > idleTimeout) {
                    HttpURLConnection connection = entry.getKey();
                    if (availableConnections.remove(connection) != null) {
                        connection.disconnect();
                        totalConnections.decrementAndGet();
                        cleaned++;
                    }
                }
            }
            
            return cleaned;
        }
        
        /**
         * 检查连接池是否为空
         */
        public boolean isEmpty() {
            return totalConnections.get() == 0;
        }
        
        /**
         * 获取连接池状态
         */
        public String getStatus() {
            return String.format("总连接: %d, 可用连接: %d", 
                totalConnections.get(), availableConnections.size());
        }
        
        /**
         * 关闭连接池
         */
        public void shutdown() {
            for (HttpURLConnection connection : availableConnections.keySet()) {
                try {
                    connection.disconnect();
                } catch (Exception e) {
                    // 忽略关闭时的错误
                }
            }
            availableConnections.clear();
            totalConnections.set(0);
        }
    }
}